﻿using System;
using System.Collections.Generic;
using System.Data;
using SdmxMl.Common;
using SdmxMl.Manager;
using SdmxMl.Structure;

namespace SdmxMl.SanteSuisse
{
    public class QuestionBlocList : List<QuestionBloc>
    {
        public ConceptSchemeType _csGen;
        #region Internal Members

        private DataTable _dtWorksheet;
        private Dictionary<string, string> dicoBlocs;
        private Dictionary<string, string> dicoCodeLists;


        #endregion //Internal Members

        public QuestionBlocList(DataTable dtWorksheet)
        {
            _dtWorksheet = dtWorksheet;
            dicoBlocs = new Dictionary<string, string>();
            dicoCodeLists = new Dictionary<string, string>(128);
        }

        public void GetQuestions()
        {
            int row = 0;
            do
            {
                QuestionBloc qb = new QuestionBloc(row, _dtWorksheet);
                if (qb.VarsList.Count > 0)
                {
                    string parentId = qb.VarsList[0].Substring(0, 5);
                    if (dicoBlocs.ContainsKey(parentId) == false)
                        dicoBlocs.Add(parentId, qb.Theme);

                    this.Add(qb);
                }
                row = qb.NextQuestionRow;
            } while (row < _dtWorksheet.Rows.Count);
        }

        public Dictionary<string, string> FillConceptScheme(SdmxMl.Manager.SmManager sm, Dictionary<string, string> dico)
        {
            bool uniqueSubId = false;
            if (dico != null)
                dicoCodeLists = dico;

            ConceptSchemeType cst = new ConceptSchemeType();
            cst.Id = "CS_SGB_Q2";
            cst.AgencyId = "OFS_RUG_GESB_GRP";
            cst.Name.UpdateDefaultText("Enquête suisse sur la santé");
            cst.Name.UpdateForLanguage("en", "Swiss Health Survey");
            cst.Name.UpdateForLanguage("de", "Schweizerische Gesundheitbefragung");
            cst.Name.UpdateForLanguage("it", "Indagine sulla salute in Svizzera");

            // If it already exists we update for another language
            ConceptSchemeType cstPrev = sm.GetArtefact(
                new ArtefactRefTyped(SdmxMl.Manager.SdmxArtefactType.Concepts, cst.FullIdent)) as ConceptSchemeType;
            if (cstPrev != null)
            {
                _csGen = cstPrev;
                // Update parents
                foreach (KeyValuePair<string, string> pair in dicoBlocs)
                {
                    ConceptType c = cstPrev.ConceptList.LocateItem(pair.Key) as ConceptType;
                    if (c != null)
                        c.Name.UpdateForCurrentLanguage(pair.Value);
                }

              //  UpdateConcept
                foreach (QuestionBloc qb in this)
                {
                    uniqueSubId = false;
                    if (qb.VarsList.Count == 2)
                    {
                        qb.VarsList.Remove(qb.VarsList[0]);
                        uniqueSubId = true;
                    }

                    for (int i = 0; i < qb.VarsList.Count; i++)
                    {
                        ConceptType c = cstPrev.ConceptList.LocateItem(qb.VarsList[i]) as ConceptType;
                        if (c != null)
                        {
                            if (i == 0 && string.IsNullOrEmpty(qb.Question) == false)
                            {
                                Annotation ann = c.AnnotationList.GetAnnotationType("QUESTION", 1);
                                if (ann != null)
                                    ann.Text.UpdateForCurrentLanguage(qb.Question);
                            }

                            if (i == 0 && string.IsNullOrEmpty(qb.Remark) == false)
                            {
                                Annotation ann = c.AnnotationList.GetAnnotationType("SRC/NOTICE", 1);
                                if (ann != null)
                                    ann.Text.UpdateForCurrentLanguage(qb.Remark);
                            }
                            if (i == 0 && string.IsNullOrEmpty(qb.Usage) == false)
                            {
                                Annotation ann = c.AnnotationList.GetAnnotationType("USAGE", 1);
                                if (ann != null)
                                    ann.Text.UpdateForCurrentLanguage(qb.Usage);
                            }

                            if (string.IsNullOrEmpty(qb.Interviewer) == false && i == 0)
                            {
                                Annotation ann = c.AnnotationList.GetAnnotationType("INT", 1);
                                if (ann != null)
                                    ann.Text.UpdateForCurrentLanguage(qb.Interviewer);
                            }

                            if (i > 0 && qb.VarsList[i].Length == 8)
                            {
                                Annotation ann = c.AnnotationList.GetAnnotationType("QUESTION", 1);
                                if (ann != null)
                                    ann.Text.UpdateForCurrentLanguage(qb.VarsListName[i]);
                            }

                            //Update Codelist if required
                            if (i == 0 && qb.DicoCodeList.Count > 0)
                            {
                                if (dicoCodeLists.ContainsKey(c.Name.ToString()))
                                {
                                    ArtefactRefTyped art = new ArtefactRefTyped(SdmxArtefactType.CodeLists, dicoCodeLists[c.Name.ToString()]);
                                    CodeListType clt = sm.GetArtefact(art) as CodeListType;
                                    if (clt != null && clt.Id.Substring(3) == c.Id)
                                        UpdateCodeText(clt.CodeList, qb.DicoCodeList);
                                }

                                // Update code quality
                                if (qb.DicoCodeQuality.Count > 0)
                                {
                                    foreach (KeyValuePair<string, string> kvpQual in qb.DicoCodeQuality)
                                    {
                                        AnnotationList anl = c.AnnotationList.GetAllAnnotationOfType("CODE_QUALITY", kvpQual.Key);
                                        if (anl != null && anl.Count > 0)
                                            anl[0].Text.UpdateForCurrentLanguage(kvpQual.Value);
                                    }
                                }
                            }
                        }

                    }
                }
            }
            else
            {
                sm.PutArtefact(SdmxArtefactType.Concepts, cst);

                // Create parents
                foreach (KeyValuePair<string, string> pair in dicoBlocs)
                {
                    ConceptType c = new ConceptType();
                    c.Id = pair.Key;
                    c.Name.UpdateDefaultText(pair.Value);
                    cst.ConceptList.Add(c);
                }

                cst.ConceptList.HasHierarchy = true;

                foreach (QuestionBloc qb in this)
                {
                    uniqueSubId = false;
                    if (qb.VarsList.Count == 2)
                    {
                        // Create an intermediate parent (if not already present)
                        string cname = qb.VarsList[1].Substring(0, 7);
                        if (cst.ConceptList.LocateItem(cname) == null)
                        {
                            ConceptType c = new ConceptType();
                            c.Id = cname;
                            c.Parent = cname.Substring(0, 5);
                            c.Name.UpdateDefaultText("Group " + qb.No);
                            cst.ConceptList.Add(c);
                        }

                        qb.VarsList.Remove(qb.VarsList[0]);
                        uniqueSubId = true;
                    }

                    for (int i = 0; i < qb.VarsList.Count; i++)
                    {
                        ConceptType c = new ConceptType();
                        string variable = qb.VarsList[i];

                        if (i == 0 && string.IsNullOrEmpty(qb.Usage) == false)
                        {
                            Annotation ann = new Annotation("USAGE");
                            ann.Text.UpdateDefaultText(qb.Usage);
                            c.AnnotationList.Add(ann);
                        }

                        if (i == 0 && string.IsNullOrEmpty(qb.Question) == false)
                        {
                            Annotation ann = new Annotation("QUESTION");
                            ann.Text.UpdateDefaultText(qb.Question);
                            c.AnnotationList.Add(ann);
                        }

                        if (string.IsNullOrEmpty(qb.Module) == false)
                        {
                            Annotation ann = new Annotation("MODULE");
                            ann.Text.UpdateDefaultText(qb.Module);
                            c.AnnotationList.Add(ann);
                        }

                        if (string.IsNullOrEmpty(qb.Interviewer) == false && (variable.Length != 8 || uniqueSubId))
                        {
                            Annotation ann = new Annotation("INT");
                            ann.Text.UpdateDefaultText(qb.Interviewer);
                            c.AnnotationList.Add(ann);
                        }

                        c.Id = variable;
                        c.Parent = variable.Length == 8 && i > 0 ?
                            qb.VarsList[0] : variable.Substring(0, uniqueSubId == true ? 7 : 5);

                        if (i == 0)
                        {
                            c.Name.UpdateDefaultText(qb.No);
                            Annotation ann = new Annotation("YEARS");
                            ann.Text.UpdateDefaultText(qb.SurveyYears);
                            c.AnnotationList.Add(ann);
                        }

                        else if (variable.Length == 8 && qb.VarsListName[i].Length > 1)
                        {
                            c.Name.UpdateDefaultText(qb.No + qb.VarsListName[i].Substring(0, 1));
                            Annotation ann = new Annotation("QUESTION");
                            ann.Text.UpdateDefaultText(qb.VarsListName[i]);
                            c.AnnotationList.Add(ann);
                        }

                        if (i == 0 && string.IsNullOrEmpty(qb.Remark) == false)
                        {
                            Annotation ann = new Annotation("SRC/NOTICE");
                            ann.Text.UpdateDefaultText(qb.Remark);
                            c.AnnotationList.Add(ann);
                        }

                        //Create Codelist if required
                        if (i == 0 && qb.DicoCodeList.Count > 0)
                        {
                            try
                            {
                                CodeListType clt = new CodeListType();
                                clt.Id = "CL_" + c.Id;
                                clt.AgencyId = cst.AgencyId;
                                clt.Name = new MultiLang("Codelist for " + qb.No);
                                foreach (KeyValuePair<string, string> kvp in qb.DicoCodeList)
                                {
                                    CodeType code = new CodeType();
                                    code.Id = kvp.Key;
                                    code.Name.UpdateDefaultText(kvp.Value);
                                    clt.CodeList.Add(code);

                                }
                                CodeListType cltDefined = CodelistAlreadyDefined(clt, sm);
                                if (cltDefined != null)
                                {
                                    cltDefined.Name.UpdateDefaultText(cltDefined.Name.ToString() + ", " + qb.No);
                                    c.CoreRepresentation.Id = cltDefined.Id;
                                    c.CoreRepresentation.AgencyId = cltDefined.AgencyId;
                                    dicoCodeLists.Add(c.Name.ToString(), cltDefined.FullIdent);
                                }
                                else
                                {
                                    sm.PutArtefact(SdmxMl.Manager.SdmxArtefactType.CodeLists, clt);
                                    c.CoreRepresentation.Id = clt.Id;
                                    c.CoreRepresentation.AgencyId = clt.AgencyId;
                                    dicoCodeLists.Add(c.Name.ToString(), clt.FullIdent);
                                }

                                // Now Code continue annotations
                                foreach (KeyValuePair<string, string> kvpContinue in qb.DicoCodeContinue)
                                {
                                    Annotation annCont = new Annotation("CODE_CONTINUE");
                                    annCont.Text.UpdateDefaultText(kvpContinue.Value);
                                    annCont.Title = kvpContinue.Key;
                                    c.AnnotationList.Add(annCont);
                                }

                                // Update code quality
                                if (qb.DicoCodeQuality.Count > 0)
                                {
                                    foreach (KeyValuePair<string, string> kvpQual in qb.DicoCodeQuality)
                                    {
                                        Annotation annQual = new Annotation("CODE_QUALITY");
                                        annQual.Text.UpdateDefaultText(kvpQual.Value);
                                        annQual.Title = kvpQual.Key;
                                        c.AnnotationList.Add(annQual);
                                    }
                                }

                            }
                            catch (Exception ex)
                            {
                                string s = ex.Message;
                                throw;
                            }
                        }

                        cst.ConceptList.Add(c);
                    }
                }
            }
            return dicoCodeLists;
        }

        private CodeListType CodelistAlreadyDefined(CodeListType newCodelist, SmManager sm)
        {
            ArtefactManager amgr = sm.GetArtefactManager(SdmxArtefactType.CodeLists);
            foreach (CodeListType clt in amgr.ArtefactList)
                if (SameCodes(newCodelist.CodeList, clt.CodeList))
                    return clt;
            return null;  
        }

        private bool SameCodes(CodeList a, CodeList b)
        {
            bool sameCodes = false;
            if (a.Count == b.Count)
            {
                sameCodes = true;
                for (int c = 0; c < a.Count; c++)
                    if (a[c].Id != b[c].Id ||
                        a[c].Name.ToString() != b[c].Name.ToString())
                    {
                        sameCodes = false;
                        break;
                    }
            }

            return sameCodes;
        }

        private void UpdateCodeText(CodeList oldCl, Dictionary<string, string> dicoCodes)
        {
            for (int i = 0; i < oldCl.Count; ++i)
                foreach (KeyValuePair<string, string>kvp in dicoCodes)
                {
                    if (oldCl[i].Id == kvp.Key)
                        oldCl[i].Name.UpdateForCurrentLanguage(kvp.Value);
                }
        }
    }

}
